package ciyuan.wrap;

import ciyuan.QQLogin;
import net.md_5.bungee.BungeeCord;
import net.md_5.bungee.api.CommandSender;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.api.connection.ProxiedPlayer;
import net.md_5.bungee.config.Configuration;
import net.md_5.bungee.config.ConfigurationProvider;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

public class BCWrap extends Wrapper {

    private final BCMain plugin;

    public BCWrap(Object plugin) {
        this.plugin = (BCMain) plugin;
    }

    @Override
    public void reloadConfig() {

    }

    @Override
    public void logMsg(String msg) {
        plugin.getLogger().info(msg);
    }

    @Override
    public boolean playerIsOnline(String playerName) {
        ProxiedPlayer proxiedPlayer = BungeeCord.getInstance().getPlayer(playerName);
        return proxiedPlayer != null && proxiedPlayer.isConnected();
    }

    @Override
    public File getDataFolder() {
        return plugin.getDataFolder();
    }

    @Override
    public boolean isOp(String playerName) {
        ProxiedPlayer proxiedPlayer = BungeeCord.getInstance().getPlayer(playerName);
        return proxiedPlayer != null && proxiedPlayer.hasPermission("DimensionAntiCheat.admin");
    }

    @Override
    public void asyncKickPlayer(String playerName, String reason) {
        if (playerName == null || playerName.isEmpty()) {
            return;
        }
        ProxiedPlayer proxiedPlayer = BungeeCord.getInstance().getPlayer(playerName);
        if (proxiedPlayer != null && proxiedPlayer.isConnected()) {
            proxiedPlayer.disconnect(reason);
        }
    }

    @Override
    public void disableCurrentPlugin() {
        BungeeCord.getInstance().getPluginManager().unregisterListeners(plugin);
        BungeeCord.getInstance().getScheduler().cancel(plugin);
        plugin.onDisable();
    }

    @Override
    public boolean hasPermission(String playerName, String permission) {
        ProxiedPlayer proxiedPlayer = BungeeCord.getInstance().getPlayer(playerName);
        return proxiedPlayer != null && proxiedPlayer.hasPermission(permission);
    }

    @Override
    public List<String> getOnlinePlayerNames() {
        return BungeeCord.getInstance()
            .getPlayers()
            .stream()
            .filter(ProxiedPlayer::isConnected)
            .map(ProxiedPlayer::getName)
            .collect(Collectors.toList());
    }

    @Override
    public Object loadConfig() {
        try {
            ConfigurationProvider provider = ConfigurationProvider.getProvider(net.md_5.bungee.config.YamlConfiguration.class);
            File configFile = new File(getDataFolder(), "config.yml");
            if (!configFile.exists()) {
                configFile.getParentFile().mkdirs();
                configFile.createNewFile();
            }
            return provider.load(configFile);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void saveConfig(Object config) {
        try {
            File configFile = new File(getDataFolder(), "config.yml");
            saveConfiguration(config, configFile);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public Object loadConfiguration(File dataFile) {
        try {
            if (!dataFile.exists()) {
                dataFile.createNewFile();
            }
            return ConfigurationProvider.getProvider(net.md_5.bungee.config.YamlConfiguration.class).load(dataFile);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    @Override
    public void saveConfiguration(Object config, File dataFile) throws IOException {
        ConfigurationProvider.getProvider(net.md_5.bungee.config.YamlConfiguration.class).save((Configuration) config, dataFile);
    }

    @Override
    public boolean configContainsKey(Object config, String key) {
        return ((Configuration) config).get(key, null) != null;
    }

    @Override
    public void configSetValue(Object config, String key, Object value) {
        ((Configuration) config).set(key, value);
    }

    @Override
    public List<String> configGetStringList(Object config, String key) {
        return ((Configuration) config).getStringList(key);
    }

    @Override
    public String configGetString(Object config, String key) {
        return ((Configuration) config).getString(key);
    }

    @Override
    public int configGetInt(Object config, String key) {
        return ((Configuration) config).getInt(key);
    }

    @Override
    public long configGetLong(Object config, String key) {
        return ((Configuration) config).getLong(key);
    }

    @Override
    public boolean configGetBoolean(Object config, String key) {
        return ((Configuration) config).getBoolean(key);
    }

    @Override
    public void configAddDefault(Object config, String key, Object value) {
        Configuration configuration = (Configuration) config;
        if (!configContainsKey(config, key)) {
            configuration.set(key, value);
        }
    }

    @Override
    public String getPluginVersion() {
        return plugin.getDescription().getVersion();
    }

    @Override
    public void sendMsgToSender(Object sender, String msg) {
        ((net.md_5.bungee.api.CommandSender) sender).sendMessage(msg);
    }

    @Override
    public int getGameServerPort() {
        return BungeeCord.getInstance().config.getListeners()
            .stream()
            .findAny()
            .orElseThrow(() -> new RuntimeException("找不到监听器"))
            .getHost()
            .getPort();
    }

    @Override
    public String getServerVersion() {
        return BungeeCord.getInstance().getName() + " " + BungeeCord.getInstance().getVersion();
    }

    @Override
    public Map<String, String> getOnlinePlayerAddress() {
        return BungeeCord.getInstance()
            .getPlayers()
            .stream()
            .collect(Collectors.toMap(ProxiedPlayer::getName,
                proxiedPlayer -> proxiedPlayer.getSocketAddress().toString(),
                (old, next) -> next
            ));
    }

    static class CommandReceiver implements CommandSender {
        private String result;

        @Override
        public String getName() {
            return QQLogin.PREFIX;
        }

        @Override
        public void sendMessage(String s) {
            this.result = s;
        }

        public String getResult() {
            return result;
        }

        @Override
        public void sendMessages(String... strings) {}

        @Override
        public void sendMessage(BaseComponent... baseComponents) {}

        @Override
        public void sendMessage(BaseComponent baseComponent) {}

        @Override
        public Collection<String> getGroups() {return new ArrayList<>();}

        @Override
        public void addGroups(String... strings) {}

        @Override
        public void removeGroups(String... strings) {}

        @Override
        public boolean hasPermission(String s) {
            return true;
        }

        @Override
        public void setPermission(String s, boolean b) {}

        @Override
        public Collection<String> getPermissions() {return new ArrayList<>();}
    }

    @Override
    public String executeCommand(String command) {
        CommandReceiver commandReceiver = new CommandReceiver();
        BungeeCord.getInstance().getPluginManager().dispatchCommand(commandReceiver, command);
        return commandReceiver.getResult();
    }
}
